﻿@using Fluxor.Blazor.Web.Components;
@using Microsoft.AspNetCore.Html;
@using SimpleIdServer.IdServer.Website.Resources;
@using SimpleIdServer.IdServer.Website.Stores.CertificateAuthorityStore;
@using System.Security.Cryptography.X509Certificates;
@inherits FluxorComponent
@inject IState<UpdateCertificateAuthorityState> updateCertificateAuthorityState
@inject IDispatcher dispatcher
@inject DialogService dialogService
@inject NotificationService notificationService;

<RadzenSteps>
    <Steps>
        <RadzenStepsItem Text="@Global.CertificateAuthorityType">
            <div class="row gy-4">
                @foreach (var certificateAuthorityType in CertificateAuthorityTypes)
                {
                    <div class="col-md-6">
                        <RadzenCard @onclick="() => SelectCertificateAuthorityType(certificateAuthorityType)" class="@(SelectedCertificateAuthorityType != null && SelectedCertificateAuthorityType.Name == certificateAuthorityType.Name ? "selected selectable" : "selectable")">
                            <div class="row">
                                <div class="col-md-3">
                                    @if (string.IsNullOrWhiteSpace(certificateAuthorityType.PictureUrl))
                                    {
                                        <RadzenImage Path="_content/SimpleIdServer.IdServer.Website/images/IdProvider.png" Style="width: 60px" />
                                    }
                                    else
                                    {
                                        <RadzenImage Path="@certificateAuthorityType.PictureUrl" Style="width: 60px" />
                                    }
                                </div>
                                <div class="col">
                                    <h5>@certificateAuthorityType.Name</h5>
                                    <p class="text-muted">@certificateAuthorityType.ShortDescription</p>
                                </div>
                            </div>
                        </RadzenCard>
                    </div>
                }
            </div>

            <hr />

            @if (SelectedCertificateAuthorityType != null)
            {
                <h5><RadzenIcon Icon="info" /> @SelectedCertificateAuthorityType.Name</h5>
                <p class="text-muted">@(new MarkupString(SelectedCertificateAuthorityType.Description))</p>
            }
        </RadzenStepsItem>
        <RadzenStepsItem Text="Generate" Disabled="@(SelectedCertificateAuthorityType == null)">
            @if(SelectedCertificateAuthorityType != null)
            {
                @switch(SelectedCertificateAuthorityType.Source)
                {
                    case CertificateAuthoritySources.DB:
                        <RadzenTemplateForm Submit=@GenerateCertificateAuthority TItem="AddCertificateAuthorityDB" Data=@addCertificateAuthorityDB>
                            <div>
                                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.SubjectName</RadzenText>
                                <RadzenTextBox Name="SubjectName" @bind-Value="@addCertificateAuthorityDB.SubjectName" Class="w-100"></RadzenTextBox>
                                <p class="text-muted">@((MarkupString)(Global.SubjectNameDescription))</p>
                                <RadzenRequiredValidator Component="SubjectName" Text="@Global.SubjectNameRequired"></RadzenRequiredValidator>
                            </div>
                            <div>
                                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.NumberOfDays</RadzenText>
                                <RadzenNumeric Name="NumberOfDays" @bind-Value="@addCertificateAuthorityDB.NumberOfDays" Class="w-100"></RadzenNumeric>
                                <p class="text-muted">@Global.NumberOfDaysDescription</p>
                                <RadzenNumericRangeValidator Min="1" Component="NumberOfDays" Text="@Global.ValueMustBePositive"></RadzenNumericRangeValidator>
                            </div>
                            @if(updateCertificateAuthorityState.Value.CertificateAuthority != null)
                            {
                                <div>
                                    <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.PublicPem</RadzenText>
                                    <RadzenTextArea Rows=10 Name="ClientName" Disabled=true @bind-Value="@updateCertificateAuthorityState.Value.CertificateAuthority.PublicKey" Class="w-100"></RadzenTextArea>
                                </div>
                                <div>
                                    <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.PrivatePem</RadzenText>
                                    <RadzenTextArea Rows=10 Name="ClientName" Disabled=true @bind-Value="@updateCertificateAuthorityState.Value.CertificateAuthority.PrivateKey" Class="w-100"></RadzenTextArea>
                                </div>
                            }

                            <div>
                                <RadzenButton class="mt-1" Variant="Variant.Flat" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Primary" Text="@Global.Generate" Disabled="@(updateCertificateAuthorityState.Value.IsUpdating)" />
                                <RadzenButton Click=@((args) => SaveCertificateAuthority()) class="mt-1" Variant="Variant.Flat" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" Text="@Global.Save" Disabled="@(updateCertificateAuthorityState.Value.IsUpdating || updateCertificateAuthorityState.Value.CertificateAuthority == null)" />
                            </div>                            
                        </RadzenTemplateForm>
                        break;
                    case CertificateAuthoritySources.CERTIFICATESTORE:
                        <RadzenTemplateForm Submit=@ImportCertificateAuthority TItem="ImportCertificateAuthorityForm" Data=@importCertificateAuthorityForm>
                            @if (!updateCertificateAuthorityState.Value.IsUpdating && !string.IsNullOrWhiteSpace(updateCertificateAuthorityState.Value.ErrorMessage))
                            {
                                <RadzenAlert AllowClose="false" AlertStyle="AlertStyle.Danger" ShowIcon="true" Variant="Variant.Flat" Shade="Shade.Lighter">@updateCertificateAuthorityState.Value.ErrorMessage</RadzenAlert>
                            }

                            <!-- Store location -->
                            <div>
                                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.StoreLocation</RadzenText>
                                <RadzenDropDown Name="StoreLocation" Class="w-100"
                                    Data=@Enum.GetValues(typeof(StoreLocation))
                                    TValue="StoreLocation"
                                    @bind-Value=@importCertificateAuthorityForm.StoreLocation />
                            </div>
                            <!-- Store name -->
                            <div>
                                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.StoreName</RadzenText>
                                <RadzenDropDown Name="StoreName" Class="w-100"
                                    Data=@Enum.GetValues(typeof(StoreName))
                                    TValue="StoreName"
                                    @bind-Value=@importCertificateAuthorityForm.StoreName />
                            </div>
                            <!-- Store name -->
                            <div>
                                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.FindType</RadzenText>
                                <RadzenDropDown Name="FindType" Class="w-100"
                                    Data=@Enum.GetValues(typeof(X509FindType))
                                    TValue="X509FindType"
                                    @bind-Value=@importCertificateAuthorityForm.FindType />
                            </div>
                            <!-- Find Value -->
                            <div>
                                <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.FindValue</RadzenText>
                                <RadzenTextBox Name="FindValue" @bind-Value="@importCertificateAuthorityForm.FindValue" Class="w-100"></RadzenTextBox>
                            </div>
                            @if(updateCertificateAuthorityState.Value.CertificateAuthority != null)
                            {
                                <div>
                                    <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.SubjectName</RadzenText>
                                    <RadzenTextBox Name="SubjectName" Disabled=true @bind-Value="@updateCertificateAuthorityState.Value.CertificateAuthority.SubjectName" Class="w-100"></RadzenTextBox>
                                </div>
                                <div>
                                    <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.ValidFrom</RadzenText>
                                    <RadzenDatePicker Name="ValidFrom" DateFormat="d" Disabled=true @bind-Value="@updateCertificateAuthorityState.Value.CertificateAuthority.StartDateTime" Class="w-100"></RadzenDatePicker>
                                </div>
                                <div>
                                    <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">@Global.ValidTo</RadzenText>
                                    <RadzenDatePicker Name="ValidTo" DateFormat="d" Disabled=true @bind-Value="@updateCertificateAuthorityState.Value.CertificateAuthority.EndDateTime" Class="w-100"></RadzenDatePicker>
                                </div>
                            }
                            <div>
                                <RadzenButton class="mt-1" Variant="Variant.Flat" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Primary" Text="@Global.Import" Disabled="@(updateCertificateAuthorityState.Value.IsUpdating)" />
                                <RadzenButton Click=@((args) => SaveCertificateAuthority()) class="mt-1" Variant="Variant.Flat" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" Text="@Global.Save" Disabled="@(updateCertificateAuthorityState.Value.IsUpdating || updateCertificateAuthorityState.Value.CertificateAuthority == null)" />
                            </div>
                        </RadzenTemplateForm>
                        break;
                }                
            }
        </RadzenStepsItem>
    </Steps>
</RadzenSteps>

@code {
    public record CertificateAuthorityType
    {
        public string Name { get; set; } = null!;
        public string ShortDescription { get; set; } = null!;
        public string Description { get; set; } = null!;
        public CertificateAuthoritySources Source { get; set; }
        public string PictureUrl { get; set; } = null!;
    }

    public record AddCertificateAuthorityDB
    {
        public string SubjectName { get; set; } = null!;
        public int NumberOfDays { get; set; } = 365;
    }

    public record ImportCertificateAuthorityForm
    {
        public StoreLocation StoreLocation { get; set; } = StoreLocation.LocalMachine;
        public StoreName StoreName { get; set; } = StoreName.Root;
        public X509FindType FindType { get; set; } = X509FindType.FindBySubjectName;
        public string FindValue { get; set; }
    }

    public record AddCertificateAuthorityStore
    {
        public string SubjectName { get; set; } = null!;
    }

    AddCertificateAuthorityDB addCertificateAuthorityDB { get; set; } = new AddCertificateAuthorityDB();
    ImportCertificateAuthorityForm importCertificateAuthorityForm { get; set; } = new ImportCertificateAuthorityForm();

    CertificateAuthorityType SelectedCertificateAuthorityType { get; set; } = null;

    protected override void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);
        if(firstRender)
        {
            SubscribeToAction<GenerateCertificateAuthorityFailureAction>((act) =>
            {
                notificationService.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = act.ErrorMessage });
                StateHasChanged();
            });
            SubscribeToAction<SaveCertificateAuthoritySuccessAction>((act) =>
            {
                dialogService.Close();
                notificationService.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = Global.CertificateAuthoritySaved });
                StateHasChanged();
            });
            SubscribeToAction<SaveCertificateAuthorityFailureAction>((act) =>
            {
                notificationService.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = act.ErrorMessage });
                StateHasChanged();
            });
        }
    }

    public ICollection<CertificateAuthorityType> CertificateAuthorityTypes = new List<CertificateAuthorityType>
    {
        new CertificateAuthorityType { Name = Global.Generate, ShortDescription = Global.GenerateCAName, Description = Global.GenerateCADescription, Source = CertificateAuthoritySources.DB, PictureUrl = "_content/SimpleIdServer.IdServer.Website/images/db.png" },
        new CertificateAuthorityType { Name = Global.CertificateStore, ShortDescription = Global.UseCertificateStoreName, Description = Global.UseCertificateStoreDescription, Source = CertificateAuthoritySources.CERTIFICATESTORE, PictureUrl = "_content/SimpleIdServer.IdServer.Website/images/certificatestore.png" }
    };

    void SelectCertificateAuthorityType(CertificateAuthorityType type)
    {
        SelectedCertificateAuthorityType = type;
        dispatcher.Dispatch(new StartAddCertificateAuthorityAction());
    }

    void GenerateCertificateAuthority(AddCertificateAuthorityDB certificateAuthority)
    {
        var act = new GenerateCertificateAuthorityAction { SubjectName = certificateAuthority.SubjectName, NumberOfDays = certificateAuthority.NumberOfDays };
        dispatcher.Dispatch(act);
    }

    void ImportCertificateAuthority(ImportCertificateAuthorityForm certificateAuthority)
    {
        var act = new ImportCertificateAuthorityAction { FindType = certificateAuthority.FindType, FindValue = certificateAuthority.FindValue, StoreLocation = certificateAuthority.StoreLocation, StoreName = certificateAuthority.StoreName };
        dispatcher.Dispatch(act);
    }

    void SaveCertificateAuthority()
    {
        var act = new SaveCertificateAuthorityAction { CertificateAuthority = updateCertificateAuthorityState.Value.CertificateAuthority };
        dispatcher.Dispatch(act);        
    }
}